import { Injectable, BadRequestException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import COS from 'cos-nodejs-sdk-v5';
import { v4 as uuidv4 } from 'uuid';
import { FileUploadResponseDto, UploadConfigResponseDto } from './dto/user.dto';

// 允许的图片类型
const ALLOWED_IMAGE_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];

// 允许的视频类型
const ALLOWED_VIDEO_TYPES = ['video/mp4', 'video/webm', 'video/ogg'];

// 允许的音频类型
const ALLOWED_AUDIO_TYPES = ['audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/ogg', 'audio/m4a'];

// 最大文件大小
const MAX_IMAGE_SIZE = 100 * 1024 * 1024; // 100MB
const MAX_VIDEO_SIZE = 5000 * 1024 * 1024; // 5GB
const MAX_AUDIO_SIZE = 100 * 1024 * 1024; // 100MB

@Injectable()
export class UploadService {
  constructor(private readonly configService: ConfigService) {}

  /**
   * 获取COS客户端
   */
  private getCOSClient(): COS {
    const secretId = this.configService.get<string>('TENCENT_CLOUD_SECRET_ID');
    const secretKey = this.configService.get<string>('TENCENT_CLOUD_SECRET_KEY');
    console.log(secretId, secretKey,'secretId, secretKey');

    if (!secretId || !secretKey) {
      throw new BadRequestException('腾讯云COS配置不完整');
    }

    return new COS({
      SecretId: secretId,
      SecretKey: secretKey,
      Protocol: 'https:',
      FileParallelLimit: 3,
      ChunkParallelLimit: 3,
      ChunkSize: 1024 * 1024,
      Timeout: 60000,
      // 添加多可用区支持
      UseAccelerate: false, // 确保不使用加速域名
      ForcePathStyle: false, // 使用虚拟主机样式
    });
  }

  /**
   * 验证文件类型和大小
   */
  private validateFile(file: Express.Multer.File): { fileType: string; maxSize: number } {
    const isImage = ALLOWED_IMAGE_TYPES.includes(file.mimetype);
    const isVideo = ALLOWED_VIDEO_TYPES.includes(file.mimetype);
    const isAudio = ALLOWED_AUDIO_TYPES.includes(file.mimetype);

    if (!isImage && !isVideo && !isAudio) {
      throw new BadRequestException(
        '不支持的文件类型，请上传 JPG、PNG、GIF、WebP 格式的图片，MP4、WebM、OGG 格式的视频，或 MP3、WAV、OGG、M4A 格式的音频'
      );
    }

    let fileType = 'images';
    let maxSize = MAX_IMAGE_SIZE;

    if (isVideo) {
      fileType = 'videos';
      maxSize = MAX_VIDEO_SIZE;
    } else if (isAudio) {
      fileType = 'audios';
      maxSize = MAX_AUDIO_SIZE;
    }

    if (file.size > maxSize) {
      throw new BadRequestException(`文件大小不能超过 ${maxSize / 1024 / 1024}MB`);
    }

    return { fileType, maxSize };
  }

  /**
   * 生成文件路径
   */
  private generateFilePath(fileType: string, originalName: string): string {
    const ext = originalName.split('.').pop() || 'jpg';
    const filename = `${uuidv4()}.${ext}`;
    
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    
    return `uploads/${fileType}/${year}/${month}/${day}/${filename}`;
  }

  /**
   * 检查腾讯云COS配置是否完整
   */
  private isTencentCloudConfigured(): boolean {
    const secretId = this.configService.get<string>('TENCENT_CLOUD_SECRET_ID');
    const secretKey = this.configService.get<string>('TENCENT_CLOUD_SECRET_KEY');
    const bucket = this.configService.get<string>('TENCENT_CLOUD_COS_BUCKET');
    const region = this.configService.get<string>('TENCENT_CLOUD_COS_REGION');
    
    return !!(secretId && secretKey && bucket && region);
  }

  /**
   * 获取腾讯云COS配置
   */
  private getTencentCloudConfig(): { secretId: string; secretKey: string; bucket: string; region: string } | null {
    if (!this.isTencentCloudConfigured()) {
      return null;
    }
    
    return {
      secretId: this.configService.get<string>('TENCENT_CLOUD_SECRET_ID')!,
      secretKey: this.configService.get<string>('TENCENT_CLOUD_SECRET_KEY')!,
      bucket: this.configService.get<string>('TENCENT_CLOUD_COS_BUCKET')!,
      region: this.configService.get<string>('TENCENT_CLOUD_COS_REGION')!,
    };
  }

  /**
   * 上传文件到腾讯云COS
   */
  async uploadFile(file: Express.Multer.File): Promise<FileUploadResponseDto> {
    try {
      // 验证文件
      const { fileType } = this.validateFile(file);

      // 获取COS配置
      const cosConfig = this.getTencentCloudConfig();

      if (!cosConfig) {
        throw new BadRequestException('腾讯云COS配置不完整');
      }

      // 生成文件路径
      const cosPath = this.generateFilePath(fileType, file.originalname);

      // 如果COS配置不完整，返回临时URL（仅用于测试）
      if (!this.isTencentCloudConfigured()) {
        const tempUrl = `data:${file.mimetype};base64,${file.buffer.toString('base64')}`;
        
        return {
          url: tempUrl,
          location: tempUrl,
          filename: cosPath.split('/').pop() || '',
          originalName: file.originalname,
          size: file.size,
          type: file.mimetype,
          storage: {
            bucket: 'temp',
            region: 'local',
            key: cosPath,
            path: cosPath
          }
        };
      }

      // 上传到腾讯云COS
      const cos = this.getCOSClient();

      // 检测是否为多可用区存储桶
      const isMAZBucket = this.isMAZBucket(cosConfig.region);

      await new Promise<void>((resolve, reject) => {
        // 根据存储桶类型使用不同的上传参数
        const uploadParams: any = {
          Bucket: cosConfig.bucket,
          Region: cosConfig.region,
          Key: cosPath,
          Body: file.buffer,
          ContentType: file.mimetype,
          ContentDisposition: `inline; filename="${encodeURIComponent(file.originalname)}"`,
          StorageClass: 'STANDARD',
          CacheControl: 'max-age=31536000',
          ACL: 'public-read',
        };

        // 如果是多可用区存储桶，移除可能导致问题的参数
        if (isMAZBucket) {
          // 多可用区存储桶不支持某些参数，移除它们
          delete uploadParams.ACL; // 多可用区存储桶可能不支持ACL设置
          // 或者使用不同的存储类型
          uploadParams.StorageClass = 'STANDARD_MAZ';
        }

        cos.putObject(uploadParams, (err, _data) => {
          if (err) {
            console.error('COS上传失败:', err);
            
            let errorMessage = '文件上传失败';
            if (err.code === 'NoSuchBucket') {
              errorMessage = '存储桶不存在，请检查配置';
            } else if (err.code === 'AccessDenied') {
              errorMessage = '访问被拒绝，请检查密钥权限';
            } else if (err.message && err.message.includes('multiple availability zones')) {
              errorMessage = '存储桶配置错误，请检查存储桶类型设置';
            } else if (err.code === 'SAZOperationNotSupportOnMAZBucket') {
              errorMessage = '多可用区存储桶不支持此操作，请检查存储桶配置或联系管理员';
            } else if (err.code === 'InvalidAccessKeyId') {
              errorMessage = '密钥ID无效，请检查配置';
            } else if (err.code === 'SignatureDoesNotMatch') {
              errorMessage = '密钥签名不匹配，请检查密钥配置';
            }
            
            reject(new BadRequestException(errorMessage));
          } else {
            resolve();
          }
        });
      });

      // 获取访问URL
      const fileUrl = await new Promise<string>((resolve, reject) => {
        const urlParams: any = {
          Bucket: cosConfig.bucket,
          Region: cosConfig.region,
          Key: cosPath,
          Sign: false,
          Protocol: 'https:',
        };

        cos.getObjectUrl(urlParams, (err, data) => {
          if (err) {
            reject(new BadRequestException('获取文件访问URL失败'));
          } else {
            resolve(data.Url);
          }
        });
      });

      return {
        url: fileUrl,
        location: fileUrl,
        filename: cosPath.split('/').pop() || '',
        originalName: file.originalname,
        size: file.size,
        type: file.mimetype,
        storage: {
          bucket: cosConfig.bucket,
          region: cosConfig.region,
          key: cosPath,
          path: cosPath
        }
      };

    } catch (error) {
      if (error instanceof BadRequestException) {
        throw error;
      }
      const errorMessage = error instanceof Error ? error.message : '未知错误';
      throw new BadRequestException(`文件上传失败: ${errorMessage}`);
    }
  }

  /**
   * 检测是否为多可用区存储桶
   */
  private isMAZBucket(region: string): boolean {
    // 多可用区存储桶通常有以下特征：
    // 1. 区域名称不包含具体的可用区标识（如-1, -2等）
    // 2. 或者通过其他方式标识为多可用区
    // 这里可以根据实际情况调整判断逻辑
    
    // 方法1：检查区域名称格式
    const singleAZPattern = /^[a-z]+-[a-z]+-\d+$/; // 如 ap-beijing-1
    const multiAZPattern = /^[a-z]+-[a-z]+$/; // 如 ap-beijing
    
    if (multiAZPattern.test(region) && !singleAZPattern.test(region)) {
      return true;
    }
    
    // 方法2：通过环境变量明确指定
    const bucketType = this.configService.get<string>('TENCENT_CLOUD_BUCKET_TYPE');
    if (bucketType === 'MAZ' || bucketType === 'maz') {
      return true;
    }
    
    return false;
  }

  /**
   * 获取上传配置信息
   */
  getUploadConfig(): UploadConfigResponseDto {
    // 修复：统一使用新的配置键名
    const secretId = this.configService.get<string>('TENCENT_CLOUD_SECRET_ID');
    const secretKey = this.configService.get<string>('TENCENT_CLOUD_SECRET_KEY');
    const bucket = this.configService.get<string>('TENCENT_CLOUD_COS_BUCKET');
    const region = this.configService.get<string>('TENCENT_CLOUD_COS_REGION');

    return {
      maxImageSize: MAX_IMAGE_SIZE,
      maxVideoSize: MAX_VIDEO_SIZE,
      maxAudioSize: MAX_AUDIO_SIZE,
      allowedImageTypes: ALLOWED_IMAGE_TYPES,
      allowedVideoTypes: ALLOWED_VIDEO_TYPES,
      allowedAudioTypes: ALLOWED_AUDIO_TYPES,
      uploadPath: '/user/upload',
      cosConfig: {
        hasSecretId: !!secretId,
        hasSecretKey: !!secretKey,
        hasBucket: !!bucket,
        hasRegion: !!region,
        bucket,
        region
      }
    };
  }
}
